import os

import pygame

from PyPixelCore.Setting import *
from PyPixelCore.block.Bar import Bar
from PyPixelCore.block.SuperMultiLineTextBlock import SuperMultiLineTextBlock
from PyPixelCore.panel.PanelList import PanelList
from PyPixelCore.timer.CycleTimer import CycleTimer
from PyPixelCore.timer.OnlyTimer import OnlyTimer
"""
    EditText --> Panel --> BaseBlock
    一个界面,通过支持焦点达到输入的效果
    可以在特定时间, 特定地点展示出来的画布

    **由于存在大小改变之内的事件,每次脏绘制都等于重绘,严重影响绘制效率(为了完成方便,需要超级多行文字块的支持)
    功能:
        通过脏精灵更新
        维护内部精灵组
        支持焦点
        支持帧动画
        不支持panel的嵌套
        
        log 
        问题:
        光标位置进退位
        脏精灵优化未实装
        
        错误的删除
"""
os.environ["SDL_IME_SHOW_UI"] = "1"


class EditTextOld(PanelList):
    def __init__(self,
                 point_x,
                 point_y,
                 width,
                 height,
                 border_width=3,
                 layer=1,
                 font_size = basic_font_size,
                 font_url = basic_font_url,
                 is_alpha=False,
                 border_color=Color_type.BLACK,
                 bk_color=Color_type.WHITE):

        # 编辑文本panel内部维护的核心显示文本框
        self.text_block = SuperMultiLineTextBlock("", width - edit_block_inner_width, height - edit_block_inner_width, border_width, border_width, layer, edit_block_inner_width, is_alpha)
        self.text_block.set_border_color((255,255,255,0))
        self.text_block.set_font(font_url, font_size)
        self.text_content_pointer = 0  # 指向当前光标的逻辑位置
        self.cursor_timer = CycleTimer(basic_cursor_show_speed)

        # 输入预览
        self.input_preview_surf = None

        # 闪烁光标
        self.cursor_surf = pygame.Surface((basic_cursor_width, font_size))
        self.cursor_surf.fill(Color_type.BLACK)
        self.cursor_shine_show = False
        self.cursor_pos_index = 0

        super().__init__(width, height, point_x, point_y, border_width, layer, is_alpha, border_color, bk_color)

        self.text_block.set_bk_color(self.bk_color)

        self.add_sprites(self.text_block)
        self.event_dict[pygame.K_BACKSPACE] = [back_func, drop_back_func]
        # self.event_dict[pygame.K_UP] = [key_up, None]
        # self.event_dict[pygame.K_DOWN] = [key_down, None]
        # self.event_dict[pygame.K_LEFT] = [key_left, None]
        # self.event_dict[pygame.K_RIGHT] = [key_right, None]

        self.reload_image()

    def reload_input_preview(self, text):
        self.is_dirty = True
        self.input_preview_surf = self.text_block.font.render(text, True, self.text_block.font_color, self.bk_color)

    def _do_layout(self):
        # 重写的布局函数,如果超出了界面,就实例化bar
        self.is_dirty = True
        # 修改文本框的尺寸
        if self.bar is None:
            self.text_block.set_limit_size(limit_w=self.text_block.limit_w-bar_width)
            self.text_block.reorder_text()
        self.text_block.set_limit_size(limit_h=self.sum_height)

        # 添加bar
        if self.bar is None:
            proportion = (self.height / self.sum_height) * self.height  # 视窗长度
            self.bar = Bar(point_x=self.rect.width - self.border_width - 10, point_y=self.border_width
                           , real_height=self.height, bar_height=proportion, border_width=0)  # bar默认的宽度为10
            self.bar.collision_rect.x += self.point_x
            self.bar.collision_rect.y += self.point_y
            self.add_sprites(self.bar)
            return True
        else:
            # 如果存在bar应该修改bar的尺寸
            self.bar.reload_bar_surf((self.height / self.sum_height) * self.height)
            return False

    def _fix_bar_pos_to_cursor(self):
        # 修正bar的位置
        if not self.bar:
            return
        # fixed_pos = self.text_block.now_char_logical_pos[1] + self.text_block.font_size
        # # 在界内不做处理
        # if 1 > (self.bar.bar_process * self.sum_height - fixed_pos - self.height) / self.height > 0:
        #     return
        # else:  # 在界外修正到底部
        #     self.bar.bar_process = fixed_pos / self.sum_height
        #     self.bar.is_dirty = True

        fixed_pos = self.text_block.now_char_logical_pos[1] + self.text_block.font_size
        # 计算新的进度值，确保它不会超出0到1的范围
        new_bar_process = max(0, min(1, fixed_pos / self.sum_height))

        # 如果进度值有变化，则更新进度条
        if self.bar.bar_process != new_bar_process:
            self.bar.bar_process = new_bar_process
            self.bar.is_dirty = True

    def add_sprites(self, *sprites):
        for sprite in sprites:
            # if sprite.type in []
            self.sprites_group.add(sprite)
        self.is_dirty = True

    def _reload_image_first(self):
        self.is_dirty = False
        # 重新更新图像
        if self.is_alpha:
            self.image = pygame.Surface(
                (self.width + 2 * self.border_width, self.height + 2 * self.border_width)).convert_alpha()
        else:
            self.image = pygame.Surface((self.width + 2 * self.border_width, self.height + 2 * self.border_width))
        self.image.fill(self.bk_color)
        # print(self.bk_color)
        self.rect.size = self.image.get_rect().size
        self.bk_image = self.image.copy()

        # 绘制
        for sprite in self.sprites_group.sprites():
            sprite.draw(self.image)

        # 绘制边框
        pygame.draw.rect(self.image, self.border_color, (0, 0, self.rect.width, self.rect.height),
                         width=self.border_width)

    def reload_image(self):
        # 便利精灵组性能较低,适用性高
        for sprite in self.sprites_group.sprites():
            if sprite.is_dirty:
                # 修正位移量
                if isinstance(sprite, Bar):
                    self.bar_offset = (self.sum_height - self.height) * self.bar.bar_process
                self.is_dirty = True
            sprite.update()
        if not self.is_dirty:
            return

        self.is_dirty = False
        # 重新更新图像
        self.image = self.bk_image.copy()
        self.rect.size = self.image.get_size()
        # 绘制
        for sprite in self.sprites_group.sprites():
            if isinstance(sprite, Bar):
                self.bar.draw(self.image)
            else:
                real_y = sprite.rect[1] - self.bar_offset
                if real_y >= 0 or real_y <= self.height:  # 剪枝,只保留界内绘制
                    self.image.blit(sprite.image,
                                    (sprite.rect[0], real_y, sprite.rect[2], sprite.rect[3]))
                sprite.collision_rect.y = sprite.rect[1] - self.bar_offset + self.rect[1]

        # # 绘制bar(适用性较低,性能较高,无法添加其他组)
        # if self.bar:
        #     self.bar.draw(self.image)
        # # 绘制smltb
        # real_y = self.text_block.rect[1] - self.bar_offset
        # if real_y >= 0 or real_y <= self.height:  # 剪枝,只保留界内绘制
        #     self.image.blit(self.text_block.image,
        #                     (self.text_block.rect[0], real_y, self.text_block.rect[2], self.text_block.rect[3]))
        # self.text_block.collision_rect.y = self.text_block.rect[1] - self.bar_offset + self.rect[1]

        # 绘制预输入提示
        if self.input_preview_surf:
            self.image.blit(self.input_preview_surf,
                            (self.text_block.now_char_logical_pos[0] + self.border_width,
                               self.text_block.now_char_logical_pos[1] + self.border_width - self.bar_offset))

        # 绘制光标
        if self.is_focus:
            if self.cursor_shine_show:
                self.image.blit(self.cursor_surf,
                                (self.text_block.now_char_logical_pos[0] + self.border_width,
                                 self.text_block.now_char_logical_pos[1] + self.border_width - self.bar_offset))

        # 绘制边框
        pygame.draw.rect(self.image, self.border_color, (0, 0, self.rect.width, self.rect.height),
                         width=self.border_width)

    def _detection_each_blit(self):
        """
            未验证是否需要缩减bar
        :return:
        """
        # 检测是否需要追加和光标位置
        t_state = False
        if self.text_block.each_char_logical_pos[-1][1] + self.text_block.font_size > self.text_block.limit_h:
            self.sum_height = self.text_block.each_char_logical_pos[-1][1] + self.text_block.font_size
            # 如果超出边界则重新布局
            t_state = self._do_layout()
        self._fix_bar_pos_to_cursor()
        return t_state

    def set_text_content(self, text):
        # 开销最大,不建议经常使用
        self.text_block.is_dirty = True
        self.text_block.set_text_content(text)
        return self._detection_each_blit()

    # def add_char(self, char):
    #     # 开销小
    #     self.is_dirty = True
    #     self.text_block.blit_a_char(char)
    #     return self._detection_each_blit()

    def delete_char(self):
        self.text_block.is_dirty = True
        if self.cursor_pos_index == len(self.text_block.char_arr):
            if self.text_block.delete_char_at_end():
                self.cursor_pos_index -= 1
        else:
            if self.text_block.delete_char_at_index(self.cursor_pos_index):
                self.cursor_pos_index -= 1
        return self._detection_each_blit()

    def add_text(self, text):
        self.text_block.blit_text_at_index(text, self.cursor_pos_index)
        self.cursor_pos_index += len(text)
        self.is_dirty = True
        return self._detection_each_blit()

    def find_now_char_pos(self, real_pos):
        # 鼠标特供的寻找位置函数
        # 由于可能会进行中间部分的删除,需要找到当前now_char_logical_pos对应的位置,方便修改
        return_value = None
        logical_pos = [real_pos[0] - self.rect[0] - self.border_width,
                       real_pos[1] - self.rect[1] - self.border_width + int(self.bar_offset)]
        # 跳过界外点
        if logical_pos[0] <= 0 or logical_pos[1] <= 0:
            return return_value

        if logical_pos[1] <= self.text_block.border_width:
            return return_value

        before_pos = None
        break_state = False
        pos_index = -1
        for each_pos_s in self.text_block.each_cursor_char_logical_pos:
            # 对极端右侧的特殊判断
            if len(each_pos_s) == 2:
                if each_pos_s[0][1] < logical_pos[1] < each_pos_s[1][1] and each_pos_s[0][0] < logical_pos[0]:
                    before_pos = each_pos_s[0]
                    pos_index += 1
                    break
            pos_index += 1
            for each_pos in each_pos_s:
                # 只在高度对等的行判断
                if logical_pos[1] - each_pos[1] <= self.font_size + self.text_block.line_interval:
                    if before_pos is None:
                        before_pos = each_pos
                        continue
                    half_width = int((each_pos[0] - before_pos[0]) / 2)
                    logical_difference = logical_pos[0] - before_pos[0]  # 与目标点的横向差值

                    if logical_difference <= half_width:  # 处理找到目标且在左边的情况
                        break_state = True
                        pos_index -= 1
                        break
                    elif half_width <= logical_difference <= 2*half_width:  # 处理找到目标且在右边的情况
                        before_pos = each_pos
                        break_state = True
                        break
                    else:
                        before_pos = each_pos
            if break_state:
                break

        # 维护pos_index
        self.cursor_pos_index = pos_index
        # 特殊处理处于最后一位的情况
        # self.reset_cursor_pos(before_pos)
        if pos_index == len(self.text_block.char_arr):
            self.reset_cursor_pos(self.text_block.each_char_logical_pos[-1])
        else:
            if before_pos is None:  # 剪枝无关项
                return return_value
            self.reset_cursor_pos(before_pos)
        return return_value

    def reset_cursor_pos(self, real_pos):
        # 定位并设置光标位置
        self.text_block.now_char_logical_pos = real_pos.copy()
        self.cursor_shine_first()
        self.is_dirty = True

    def focus_animation(self, pos):
        self.find_now_char_pos(pos)
        if not self.is_focus:
            # 将输入框放置在光标下方某处
            pygame.key.start_text_input()
            input_rect = (pygame.Rect
                          (self.text_block.now_char_logical_pos[0] + self.point_x + 10, self.text_block.now_char_logical_pos[1] + self.point_y, 200, self.font_size + 10))
            pygame.key.set_text_input_rect(input_rect)
            self.cursor_shine_first()
            self.set_timer_animation(self.cursor_timer, cursor_shine)
        super().focus_animation(pos)

    def leave_focus_animation(self, pos):
        pygame.key.stop_text_input()
        self.input_preview_surf = None
        self.delete_timer_animation(cursor_shine)
        super().leave_focus_animation(pos)

    @property
    def font_size(self):
        return self.text_block.font_size

    def cursor_shine_first(self):
        # 重置光标的闪烁状态
        self.is_dirty = True
        self.cursor_timer.reset()
        self.cursor_shine_show = True

    def get_text(self):
        return "".join(self.text_block.char_arr)


def cursor_shine(self):
    self.is_dirty = True
    self.cursor_shine_show = not self.cursor_shine_show

def back_func_help(self: EditTextOld):
    # back键的帮助函数
    self.is_dirty = True
    self.delete_char()

def back_func_help_help(self:EditTextOld):
    # back_help的帮助函数,用于激活帮助函数的动画
    self.set_timer_animation(CycleTimer(basic_delete_speed), back_func_help)

def back_func(self: EditTextOld):
    # back键按下事件
    self.delete_char()
    self.delete_timer_animation(cursor_shine)
    self.cursor_shine_first()
    self.set_timer_animation(OnlyTimer(basic_first_delete_wait), back_func_help_help)

def drop_back_func(self: EditTextOld):
    # back键松开事件
    self.delete_timer_animation(back_func_help)
    self.delete_timer_animation(back_func_help_help)
    self.cursor_shine_first()
    self.set_timer_animation(self.cursor_timer, cursor_shine)

# 不支持,这个模型太复杂,不支持鼠标移动
# def key_up(self: EditText):
#     # 上箭头键事件
#     pos_arr = self.text_block.each_char_logical_pos[self.cursor_pos_index]
#     real_pos = [pos_arr[0] + self.point_x + self.border_width
#                 , pos_arr[1] + self.point_y + self.border_width - self.bar_offset - self.text_block.line_interval - 1]
#     self.text_block.is_dirty = True
#     self.find_now_char_pos(real_pos)
#     if self.text_block.char_arr[self.cursor_pos_index - 1] == "\n":
#         self.cursor_pos_index -= 1
#
# def key_down(self: EditText):
#     # 下箭头键事件
#     pos_arr = self.text_block.each_char_logical_pos[self.cursor_pos_index]
#     real_pos = [pos_arr[0] + self.point_x + self.border_width
#                 , pos_arr[1] + self.point_y + self.border_width + 1 + self.font_size + self.text_block.line_interval - self.bar_offset]
#     self.find_now_char_pos(real_pos)
#     self.text_block.is_dirty = True
#
# def key_left(self: EditText):
#     # 左箭头键事件
#     if self.cursor_pos_index == 0:
#         return
#     before_index = self.cursor_pos_index
#     pos_arr = self.text_block.each_char_logical_pos[self.cursor_pos_index - 1]
#     real_pos = [pos_arr[0] + self.point_x + self.border_width + self.text_block.border_width - self.text_block.word_interval
#         , pos_arr[1] + self.point_y + self.border_width + self.text_block.line_interval + self.text_block.border_width - self.bar_offset]
#     self.find_now_char_pos(real_pos)
#     self.text_block.is_dirty = True
#
# def key_right(self: EditText):
#     # 右箭头键事件
#     if self.cursor_pos_index >= len(self.text_block.char_arr):
#         return  # 剪枝末尾
#     pos_arr = self.text_block.each_char_logical_pos[self.cursor_pos_index + 1]
#     real_pos = [pos_arr[0] + self.point_x + self.border_width + self.text_block.border_width,
#                 pos_arr[1] + self.point_y + self.border_width + self.text_block.border_width - self.bar_offset]
#     self.find_now_char_pos(real_pos)
#     self.text_block.is_dirty = True








